/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.sensor;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.filechooser.FileFilter;
import org.apache.commons.io.FileUtils;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.api.progress.aggregate.AggregateProgressFactory;
import org.netbeans.api.progress.aggregate.AggregateProgressHandle;
import org.netbeans.api.progress.aggregate.ProgressContributor;
import org.openide.filesystems.FileChooserBuilder;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.NbBundle;

/**
 *
 * @author Timon Veenstra
 */
public class SensorFilePicker implements ActionListener {

    private final Lookup.Result<SensorProcessorProvider> sensorProcessorProviderResult = Lookup.getDefault().lookupResult(SensorProcessorProvider.class);
    private final ProxyFileFilter filterAllSensors = new ProxyFileFilter();
    private final String title = NbBundle.getMessage(this.getClass(), "sensor.filepicker.title");
    private final String approve = NbBundle.getMessage(this.getClass(), "sensor.filepicker.approve");
    private final String processProcessTitle = NbBundle.getMessage(this.getClass(), "sensor.process.process.title");
    private final List<File> processQueue = Collections.synchronizedList(new ArrayList<File>());
    private final List<File> copyQueue = Collections.synchronizedList(new ArrayList<File>());

    public SensorFilePicker() {
        sensorProcessorProviderResult.addLookupListener(new LookupListener() {

            @Override
            public void resultChanged(LookupEvent ev) {
                synchronized (filterAllSensors) {
                    filterAllSensors.reset();
                    for (SensorProcessorProvider processorProvider : ((Lookup.Result<SensorProcessorProvider>) ev.getSource()).allInstances()) {
                        filterAllSensors.addFilter(createFileFilterForProcessor(processorProvider));
                    }
                }
            }
        });
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        File workingDirectory = new File(SensorPreference.LAST_DIR.getValue());

        FileChooserBuilder fsb = new FileChooserBuilder("Cropcircle-directory");
        fsb.setTitle(title);
        fsb.setDefaultWorkingDirectory(workingDirectory);
        fsb.setApproveText(approve);

        for (SensorProcessorProvider processorProvider : Lookup.getDefault().lookupAll(SensorProcessorProvider.class)) {
            fsb.addFileFilter(createFileFilterForProcessor(processorProvider));
        }

        File selectedFile = fsb.showOpenDialog();
        //
        // if cancel is pressed, selected file will be null. return in that case
        if (selectedFile == null){
            return;
        }

        if (selectedFile.isDirectory()) {
            synchronized (filterAllSensors) {
                copyQueue.addAll(Arrays.asList(selectedFile.listFiles(filterAllSensors)));
            }
        } else if (selectedFile.isFile()) {
            copyQueue.add(selectedFile);
        }

//        AggregateProgressHandle handle = AggregateProgressFactory.createHandle(processProcessTitle, new ProgressContributor[]{}, null, null);
//        handle.start();
        //
        // start copy process
        //
        synchronized (processQueue) {
            File archiveDir = new File(SensorPreference.ARCHIVE.getValue());
            if (!archiveDir.exists()) {
                archiveDir.mkdirs();
            }
            for (File file : copyQueue) {
                try {
                    StringBuilder sb = new StringBuilder(archiveDir.getAbsolutePath());
                    sb.append("/");
                    sb.append(file.getName());
                    File archivedSensorFile = new File(sb.toString());
                    FileUtils.copyFile(file, archivedSensorFile, true);
                    processQueue.add(archivedSensorFile);

                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
            copyQueue.clear();
        }
        //
        // start processing of files
        //
        Thread processThread = new Thread(new ProcessJob());
        processThread.start();


    }

    private class ProxyFileFilter implements java.io.FileFilter {

        private final List<FileFilter> filters = new ArrayList<FileFilter>();

        @Override
        public boolean accept(File pathname) {
            for (FileFilter filter : filters) {
                if (filter.accept(pathname)) {
                    return true;
                }
            }
            return false;
        }

        public void reset() {
            filters.clear();
        }

        public void addFilter(FileFilter filter) {
            filters.add(filter);
        }
    }

    private FileFilter createFileFilterForProcessor(final SensorProcessorProvider processorProvider) {
        return new FileFilter() {

            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }
                if (f.isFile()) {
                    String name = f.getName().toLowerCase();
                    for (String extention : processorProvider.getSupportedExtentions()) {
                        if (name.endsWith(extention)) {
                            return true;
                        }
                    }
                }
                return false;
            }

            @Override
            public String getDescription() {
                return processorProvider.getFormatDescription();
            }
        };
    }

    class ProcessJob implements Runnable {
        @Override
        public void run() {
            synchronized (processQueue) {
                // system handle will give this handle less priority diplaying file handles first
                ProgressHandle progressHandle = ProgressHandleFactory.createSystemHandle(processProcessTitle);
                int progress = 0;
                progressHandle.start(processQueue.size());
                for (File file : processQueue) {

                    findprocessor:
                    for (SensorProcessorProvider processorProvider : sensorProcessorProviderResult.allInstances()) {
                        if (processorProvider.isSupported(file) && processorProvider.isValid(file)) {
                            SensorProcessor processor = processorProvider.getProcessor(file);
                            processor.process();
                            progressHandle.progress(++progress);
                            break findprocessor;
                        }
                    }
                }
                progressHandle.finish();
                processQueue.clear();
            }
        }
    }
}
